/**
 * @(#) AbstractFacedServer.java RabbitDB
 */
package cn.rabbitdb.faced.server;

import java.util.ArrayList;
import java.util.List;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;

/**
 * 前端服务器
 * 
 * @author 智慧工厂@
 *
 */
@RequiredArgsConstructor
public abstract class AbstractFacedServer extends LifecycledAdapter {
	private final int bindingPort;
	private final List<EventLoopGroup> eventLoopGroups = new ArrayList<>();

	/*
	 * (non-Javadoc)
	 * 
	 * @see java.lang.Runnable#run()
	 */
	@Override
	@SneakyThrows
	public void startup() {
		EventLoopGroup bossGroup = getEventLoop();
		EventLoopGroup workerGroup = getEventLoop();
		eventLoopGroups.clear();
		eventLoopGroups.add(bossGroup);
		eventLoopGroups.add(workerGroup);
		try {
			ServerBootstrap boot = new ServerBootstrap();
			boot.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class)
					.childHandler(new ChannelInitializer<Channel>() {
						@Override
						protected void initChannel(Channel arg0) throws Exception {
							arg0.pipeline().addLast(getChannelInboundHandlerAdapter());
						}
					}).option(ChannelOption.SO_BACKLOG, 128).childOption(ChannelOption.SO_KEEPALIVE, true);

			ChannelFuture future = boot.bind(bindingPort).sync();
			future.channel().closeFuture().sync();
		} catch (Exception e) {
			throw new RuntimeException(e);
		} finally {
			this.shutdown();
		}
	}

	/**
	 * 根据操作系统获取最优的EventLoop
	 * 
	 * @return
	 */
	protected abstract EventLoopGroup getEventLoop();

	/**
	 * 获取消息处理器
	 * 
	 * @return
	 */
	protected abstract ChannelInboundHandlerAdapter getChannelInboundHandlerAdapter();

	@Override
	public void shutdown() {
		this.eventLoopGroups.forEach(x -> x.shutdownGracefully());
	}
}
